package pl.edu.mimuw.mas.agent.behaviour.hunting.hunter;

import jade.core.AID;
import jade.core.behaviours.OneShotBehaviour;
import jade.core.behaviours.SequentialBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.lang.acl.UnreadableException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import pl.edu.mimuw.mas.agent.DogAgent;
import pl.edu.mimuw.mas.agent.HunterAgent;
import pl.edu.mimuw.mas.agent.HuntingAgent;
import pl.edu.mimuw.mas.agent.behaviour.ReplyWaitingBehaviour;
import pl.edu.mimuw.mas.message.PositionMessage;
import pl.edu.mimuw.mas.message.ScareFactorMessage;
import pl.edu.mimuw.mas.util.Position;
import pl.edu.mimuw.mas.util.Time;

public class GroupPairingBehaviour extends SequentialBehaviour {

	private static final long serialVersionUID = -3028402008306713063L;
	
	protected final Logger logger = LoggerFactory.getLogger(getClass());
	
	private List<ACLMessage> replies = new ArrayList<ACLMessage>();
	
	public GroupPairingBehaviour(HunterAgent a) {
		super(a);
		
		// prosze o info o straszeniu
		addSubBehaviour(new OneShotBehaviour(a) {

			private static final long serialVersionUID = -7355517923277235986L;

			@Override
			public void action() {
				HunterAgent a = (HunterAgent) myAgent;
				
//				logger.debug("{} : proszę o info o współczynniku straszenia", a.getName());
				
				ACLMessage request = new ACLMessage(ACLMessage.REQUEST);
				
				try {
					Position p = a.getAvgGroupPosition();
					request.setContentObject(new PositionMessage(a.getAID(), p.x, p.y));
					request.setConversationId(DogAgent.SCARE_FACTOR_CONV);
				} catch (IOException e) {
					logger.error("{} : błąd podczas serializacji wiadomości", a.getName(), e);
				}
				
				DFAgentDescription template = new DFAgentDescription();
				// agent jest psem
		  		ServiceDescription sdDog = new ServiceDescription();
		  		sdDog.setType(DogAgent.DOG_SERVICE_TYPE);
		  		template.addServices(sdDog);
		  		// oraz liderem
		  		ServiceDescription sdLeader = new ServiceDescription();
		  		sdLeader.setType(HuntingAgent.LEADER_SERVICE_TYPE);
		  		template.addServices(sdLeader);
		  		  		
				try {
					DFAgentDescription[] results = DFService.search(a, template);
					for (int i = 0; i < results.length; i++) {
			  			request.addReceiver(results[i].getName());
			  		}
				} catch (FIPAException e) {
					logger.error("{} : błąd FIPA", a.getName(), e);
				}
				
				a.send(request);
			}
			
		});
		
		// czekam na odpowiedzi
		MessageTemplate mt = MessageTemplate.and(
				MessageTemplate.MatchConversationId(DogAgent.SCARE_FACTOR_CONV),
				MessageTemplate.MatchPerformative(ACLMessage.INFORM));
		addSubBehaviour(new ReplyWaitingBehaviour(a, mt, Time.MESSAGE_REPLY_WAIT, replies));
		
		// wybieram najlepszą grupę
		addSubBehaviour(new OneShotBehaviour(a) {

			private static final long serialVersionUID = 7798053569978704537L;

			@Override
			public void action() {
				HunterAgent a = (HunterAgent) myAgent;
				
				ScareFactorMessage sm;
				double bestScareFactor = 0.5; // odpowiada pi/2; najniższa rozsądna wartość straszenia; dla mniejszej łoś się oddala
				AID bestPairedLeader = null;
				for (ACLMessage reply : replies) {
					try {
						sm = (ScareFactorMessage) reply.getContentObject();
						if (sm.scareFactor > bestScareFactor) {
							bestScareFactor = sm.scareFactor;
							bestPairedLeader = sm.getAID();
						}
					} catch (UnreadableException e) {
						logger.error("{} : UnreadableException {}", a.getName(), e);
					}
				}
				a.setScareFactor(bestScareFactor);
				a.setPairedLeader(bestPairedLeader);
				
				if (bestPairedLeader != null) {
					logger.debug("{} : najlepszą parą jest {} ze współczynnikiem " + bestScareFactor,
							a.getName(), bestPairedLeader.getName());
				} else {
					logger.debug("{} : nie znalazłem nikogo do pary ;(", a.getName());
				}
			}
			
		});
		
	}

}
